package Stack::SMC6824M;

use strict;

use lib '..';

use Data::Dumper;
use Utils;
use NetAddr::IP;

use Conf; my $conf = Conf->show;

use base qw (Stack);

# SMC6824M MIB - v novsich verziach firmware akoby to nebolo, preto som v tomto pripade zavrhol SNMP a presiel na telnet
#my $smcSwitches = 'enterprises.202.20';
#        my $smc6824mMIB = $smcSwitches.'.28';
#                my $smc6824mMIBObjects = $smc6824mMIB.'.1';
#                        my $aclMgt = $smc6824mMIBObjects.'.17.7';
#

my $time_before;		# kvoli pocitaniu doby trvania jednotlivych operacii

sub initialize {
	# NEZMAZAT!!! inak bude deep recursion
}

sub get_serial_number {
	my $self = shift;
	my ($unit) = @_;
	my $OID = "mib-2.47.1.1.1.1.11.".(200+$unit);
	return $self->SNMPget($OID);
}

sub SNMPgetMAClist {	# na rozdiel od Cisco Catalyst 2950, pri SMC netreba uvadzat vlan_id
        my $self = shift;
        my ($vlan_id) = @_;
        return $self->SNMPwalk("mib-2.17.4.3.1.2");
}

sub MAC2Port {		# na rozdiel od Cisco Catalyst 2950, pri SMC netreba uvadzat vlan_id
        my $self = shift;
        my ($MACdec, $vlan_id) = @_;
        return $self->SNMPget("mib-2.17.4.3.1.2.$MACdec") || 0;
}

sub switch_internal_port_count {
        my $self = shift;
        return 32;
}


sub main_uplink {       # zavadzame konvenciu, ze na SMC6824M stohoch bude VZDY uplinkovy port 1/26 !!
        my $self = shift;
        my $unit = 1;
        my $port = 26;
        return ($unit, $port);
}

sub CLI_prompt {
	my $self = shift;
#	return '>';	# prihlasenie do oper modu
	return '#';	# prihlasenie do enable modu
}

sub CLI_configure {
	my $self = shift;
	my ($commands) = @_;
	return $self->cmd("end\nconfigure\n$commands\nend\n");
}

sub CLI_quit {
	my $self = shift;
	return "end\nexit\n";
}

sub CLI_saveconfig {
	my $self = shift;
	my $config_name = $self->standard_conf_filename;
	return "end\ncopy running-config startup-config\n$config_name\n";
}

sub CLI_show_interface {
	my $self = shift;
	my ($unit,$port) = @_;
	my @status = $self->cmd("show interfaces status ethernet $unit/$port\n");
	my @switchport = $self->cmd("show interfaces switchport ethernet $unit/$port\n");
	my @counters = $self->cmd("show interfaces counters ethernet $unit/$port\n \n");
#	return join("",@status)."\n".join("",@switchport)."\n".join("",@counters);
	return @status,@switchport,@counters;
}

sub translatePortNumber {	#	portnum => unit, port
        my $self = shift;
	my $period = $self->switch_internal_port_count;
        my ($num) = @_;
        my $unit = int($num/$period)+1;
        my $port = $num - $unit*$period + $period;
        return ($unit, $port);
}

sub detranslatePortNumber {	#	unit, port => portnum
        my $self = shift;
	my $period = $self->switch_internal_port_count;
        my ($unit,$port) = @_;
        return ($unit-1)*$period+$port;
}


sub extended_IPACL_name {
	my $self = shift;
	my ($unit, $port, $direction) = @_;
	# ak sa toto zmeni pocas prevadzky, mozu vo switchoch ostat reziduovat nevyuzite ACL - raz za cas treba konfiguracie prejst, ci tam nie su zbytocne ACL alebo VLAN - inak je to plytvanie zdrojmi a v pripade VLAN aj znizovanie bezpecnosti
	return "unit".Utils::addZeros($unit,2)."port".Utils::addZeros($port,2).$direction;
}

sub unbind_extended_IPACL {
	my $self = shift;
	my ($unit, $port, $direction) = @_;
	if ($direction eq 'in' || $direction eq 'out') {
		return $self->CLI_configure_interface($unit,$port,
			"no ip access-group ".$self->extended_IPACL_name($unit,$port,$direction).
											" $direction\n");
	} else {
		return '';
	}
}

sub drop_extended_IPACL {
	my $self = shift;
	my ($unit, $port, $direction) = @_;
        if ($direction eq 'in' || $direction eq 'out') {
                return $self->CLI_configure("no access-list ip extended ".
					$self->extended_IPACL_name($unit,$port,$direction)."\n");
        } else {
                return '';
        }
}

sub enter_extended_IPACL_rules {
        my $self = shift;
        my ($unit, $port, $direction, $commands) = @_;
        if ($direction eq 'in' || $direction eq 'out') {
                return $self->CLI_configure("access-list ip extended ".
				$self->extended_IPACL_name($unit,$port,$direction)."\n$commands\nexit\n");
        } else {
                return '';
        }
}

sub IPACL_deny_dhcp_server {
        my $self = shift;
        my ($unit, $port, $direction) = @_;
        return $self->enter_extended_IPACL_rules($unit,$port,$direction,
								"deny UDP any any destination-port 68\n");
}

# deprecated, ostry 8.1.2007
#sub IPACL_permit_dhcp_client {
#        my $self = shift;
#        my ($unit, $port, $direction) = @_;
#        return $self->enter_extended_IPACL_rules($unit,$port,$direction,
#								"permit any host 255.255.255.255\n");
#}

sub IPACL_permit_destinations {
        my $self = shift;
        my ($unit, $port, $direction, $destinations) = @_;
	my $rules;
	foreach my $destination (@{$destinations}) {
		my $ip = NetAddr::IP->new($destination);
		my $mask = $ip->mask; $ip = $ip->addr; 
                $rules .= "permit any $ip $mask\n";
	}
        return $self->enter_extended_IPACL_rules($unit,$port,$direction,$rules);
}

sub IPACL_permit_sources {
        my $self = shift;
        my ($unit, $port, $direction, $sources) = @_;
        my $rules;
        foreach my $source (@{$sources}) {
		my $ip = NetAddr::IP->new($source); 
		my $mask = $ip->mask; $ip = $ip->addr; 
                $rules .= "permit $ip $mask any\n";
        }
        return $self->enter_extended_IPACL_rules($unit,$port,$direction,$rules);
}

sub IPACL_deny_default {
        my $self = shift;
        my ($unit, $port, $direction) = @_;
        my $rules;
        return $self->enter_extended_IPACL_rules($unit,$port,$direction,
#				"permit host 0.0.0.0 host 255.255.255.255\ndeny any any\n");
#ked niekto ziska IP, a chce si ju obnovit, pripadne mu to
#neprideli adresu z 0.0.0.0 (teda ma automaticku privatnu alebo uz pridelenu
#a nejaku chybnu), tak pri prvidle allow 0.0.0.0 255.255.255.255 sa mu uz
#adresu nepodari obnovit, iba ak ju releasne a obnovi z 0
				"permit any host 255.255.255.255\ndeny any any\n");
}

sub bind_extended_IPACL {
        my $self = shift;
        my ($unit, $port, $direction) = @_;
        if ($direction eq 'in' || $direction eq 'out') {
                return $self->CLI_configure_interface($unit,$port,"\nip access-group ".
				$self->extended_IPACL_name($unit,$port,$direction)." $direction\n");
        } else {
                return '';
        }
}

# deprecated - pouzivat max_bitrate
#sub set_switchport_broadcast_max_packet_rate {
#	my $self = shift;
#	my ($unit, $port, $bsc) = @_;
#	if (!defined $bsc || !$bsc) {
#		return $self->CLI_configure_interface($unit,$port,"no switchport broadcast packet-rate\n");
#	} else {
#		return $self->CLI_configure_interface($unit,$port,"switchport broadcast packet-rate $bsc\n");
#	}
#}

# deprecated - nastavuje sa rucne, nie z LANmgmt, ostry 8.1.2007
#sub set_switchport_broadcast_max_bitrate {
#	my $self = shift;
#	my ($unit, $port, $bitrate) = @_;
#	if (!defined $bitrate || !$bitrate) {
#		return $self->CLI_configure_interface($unit,$port,
#						"no switchport broadcast packet-rate\n");
#	} else {
#		my $byterate = Utils::round($bitrate/8);
#		my $packetrate = Utils::round($byterate/(Utils::ethernet_max_frame_size()));
#		if ($packetrate < 500) {
#			$packetrate = 500;
#		}
#		return $self->CLI_configure_interface($unit,$port,
#						"switchport broadcast packet-rate $packetrate\n");
#	}
#}

sub set_switchport_description {
	my $self = shift;
	my ($unit, $port, $description) = @_;
	return $self->CLI_configure_interface($unit,$port,"description $description\n");
}

sub set_switchport_access_VLAN {
	my $self = shift;
	my ($unit, $port, $vlan_id) = @_;
	my $set_result = $self->CLI_configure_interface($unit,$port,
		"switchport allowed vlan add $vlan_id untagged\n".
		"switchport native vlan $vlan_id\n".
		"switchport ingress-filtering\n".
		"switchport mode hybrid\n".
		"no switchport gvrp\n"
	);
	my @show_switchport_result = $self->CLI_show("interfaces switchport ethernet $unit/$port");
	my @VLANs;
	foreach (@show_switchport_result) {	# vyparsovanie nastavenych VLAN z vystupu
		my @var_val = split ':',$_;
		if ($var_val[0] =~ /^.*Allowed VLAN$/) {
			my @raw_vlan_ids = split /\(/,$var_val[1];
			foreach (@raw_vlan_ids) {
				$_ =~ /^\D*(\d+)\D*$/;
				if ($_ != $vlan_id) {		# tu spravnu VLAN ignoruj
					push @VLANs, $1;			
				}
			}
		}
	}

	# zrus ostatne VLAN, ktore tam nemaju byt nastavene
	my $unset_result;
	foreach (@VLANs) {
		$unset_result = $self->CLI_configure_interface($unit,$port,
			"switchport allowed vlan remove $_\n"
		);
	}
}

sub CLI_show {
	my $self = shift;
	my ($what) = @_;
	return $self->cmd("show $what\n")
}

sub backupStartupConfig {
	my $self = shift;
	my $dstfile = $self->standard_conf_filename;
	my $tftp_ip=$conf->{TFTP_IP};
	$self->cmd("\ncopy startup-config tftp\n$tftp_ip\n$dstfile\n");
}

sub backupRunningConfig {
	my $self = shift;
	my $dstfile = $self->standard_conf_filename.'_running';
	my $tftp_ip=$conf->{TFTP_IP};
	$self->cmd("\ncopy running-config tftp\n$tftp_ip\n$dstfile\n");
}

sub set_static_addr_uplink {	# nastavi na zvolenej VLAN hlavneho uplinku staticku MAC (typicky default gw)
				# (bezpecnostna feature)
	my $self = shift;
	my ($MAC, $VLAN) = @_;
	my ($unit, $port) = $self->main_uplink;
	$MAC = Utils::MACcolon2minus($MAC);
	my $CLIcommand = "MAC-address-table static $MAC interface ethernet $unit/$port VLAN $VLAN permanent";
        Logger->write(__PACKAGE__." Setting $CLIcommand in global configuration mode ".$self->hostname." . . .");
	$self->cmd($self->CLI_configure($CLIcommand));
        Logger->write(__PACKAGE__." Setting $CLIcommand in global mode done.")
}

sub set_port_max_MAC_count {
        my $self = shift;
        my ($unit, $port, $count) = @_;
#	docasne disabled, kvoli vykonnostnym problemom - nastavenie 1 portu trva skoro pol minuty!
#        $self->CLI_configure_interface($unit, $port, "mac-address-table max-mac-count $count\n"); 
}

sub CLI_set_RADIUS {	# nastavi RADIUS secret key a max. 5 RADIUS serverov
	my $self = shift;
	my ($key, $host1, $host2, $host3, $host4, $host5) = @_;
	return "radius-server key $key\nno radius-server 1\nradius-server 1 host $host1\nno radius-server 2\
	radius-server 2 host $host2\no radius-server 3\nradius-server 3 host $host3\
	no radius-server 4\nradius-server 4 host $host4\nno radius-server 5\nradius-server 5 host $host5\n";
}

sub CLI_set_GVRP {	# nastavi/odstavi globalne GVRP
	my $self = shift;
	my ($turned_on) = @_;
	if ($turned_on) {
		return "bridge-ext gvrp\n";
	} else {
		return "no bridge-ext gvrp\n";

	}
}

sub CLI_set_SNTP {	# nastavi synchronizaciu hodin s casovymi servermi
	my $self = shift;
	my ($host1, $host2, $host3) = @_;
	if ($host1) {
		return "sntp server $host1 $host2 $host3\nsntp client\n";
	} else {
		return "no sntp server\nno sntp client\n";
	}
}

sub CLI_set_ident {	# nastavi na zariadeni hostname, CLI prompt, location a kontakt na admina
	my $self = shift;
	my ($hostname, $location, $admin_email) = @_;
	return "hostname $hostname\nprompt $hostname\nsnmp-server location $location\nsnmp-server contact $admin_email\n";
}

sub CLI_set_SNMPcommunity {	# nastavi rw/ro community string alebo ho odstavi
	my $self = shift;
	my ($string, $type) = @_;
	if ($type) {
		if ($type == 7) {	# 7 = read-write community string
			return "snmp-server community $string rw\n";
		} else {		# readonly community string
			return "snmp-server community $string ro\n";
		}
	} else {			# delete community string
		return "no snmp-server community $string\n";
	}
}

sub CLI_set_syslog {
	my $self = shift;
	my ($host, $off) = @_;
	if ($off) {
		return "no logging host $host\n";
	} else {
		return "logging host $host\n";
	}
}

sub CLI_set_logging {
	my $self = shift;
	my ($facility, $history_RAM, $history_flash) = @_;
	return "logging facility $facility\nlogging history RAM $history_RAM\nlogging history flash $history_flash\nlogging trap\nlogging on\n"; 
}

sub CLI_set_STP {
	my $self = shift;
	my ($mode) = @_;
	return "spanning-tree mode $mode\n";
}

sub CLI_configure_interface {
	my $self = shift;
	my ($unit, $port, $commands) = @_;
	return $self->CLI_configure("interface ethernet $unit/$port\n$commands\nexit\n");
}

1;
